<template>
  <!-- 地球容器，监听右键事件 -->
  <div class="earth" ref="earth" @contextmenu="showContextMenu"></div>
  <div class="nav-box">
    <div class="changeViewer">
      <el-button type="info" @click="switchToCesiumViewer">切换Cesium视口</el-button>
      <el-button type="info" @click="switchToUEViewer">切换UE视口</el-button>
    </div>
    <Fly :objm="objm" />
    <div class="switch">
      <span>影像显隐控制</span>
      <el-switch
        style="--el-switch-on-color: #13ce66; --el-switch-off-color: #909399"
        v-model="state"
        @change="changeImageLayerShow"
      />
    </div>
    <div class="switch">
      <span>3D模型</span>
      <el-switch
        style="--el-switch-on-color: #13ce66; --el-switch-off-color: #909399"
        v-model="tileset3d"
      />
    </div>
    <Tileset3D :objm="objm" @bim-tileset-ready="handleBIMtilesetReady" v-if="tileset3d" />
    <div class="switch">
      <span>测量</span>
      <el-switch
        style="--el-switch-on-color: #13ce66; --el-switch-off-color: #909399"
        v-model="ceLiangShow"
      />
    </div>
    <CeLiang v-if="ceLiangShow" />
    <div class="switch">
      <span>Poi标绘</span>
      <el-switch
        style="--el-switch-on-color: #13ce66; --el-switch-off-color: #909399"
        v-model="poiShow"
      />
    </div>
    <PoiSelector v-if="poiShow" :objm="objm" @poi-created="handlePoiCreated" />
    <div class="switch">
      <span>特效</span>
      <el-switch
        style="--el-switch-on-color: #13ce66; --el-switch-off-color: #909399"
        v-model="effectShow"
      />
    </div>
    <Effect v-if="effectShow" :objm="objm" />

    <div class="switch">
      <span>缩略图定位</span>
      <el-switch
        style="--el-switch-on-color: #13ce66; --el-switch-off-color: #909399"
        v-model="picViewer"
      />
    </div>
    <PictureViewer :objm="objm" v-if="picViewer" />
    <div class="switch">
      <span>多视图定位</span>
      <el-switch
        style="--el-switch-on-color: #13ce66; --el-switch-off-color: #909399"
        v-model="morePic"
      />
    </div>
    <MorePicture :objm="objm" v-if="morePic" />
    <div class="switch">
      <span>可视化参数</span>
      <el-switch
        style="--el-switch-on-color: #13ce66; --el-switch-off-color: #909399"
        v-model="visual"
      />
    </div>
    <VisualParameters v-if="visual" />

    <div class="switch">
      <span>天气</span>
      <el-switch
        style="--el-switch-on-color: #13ce66; --el-switch-off-color: #909399"
        v-model="weatherShow"
      />
    </div>
    <Weather v-if="weatherShow" />
  </div>
  <!-- 右键菜单组件 -->
  <ContextMenu ref="contextMenuRef" :objm="objm" @command="handleContextMenuCommand" />
</template>

<script setup>
import { onMounted, ref, inject } from 'vue'
import { ESWidget } from 'earthsdk3'
// import initEarthLayers from './utils/initEarthLayers.js' // 引入封装好的方法
import {
  addESImageryLayer,
  addESTerrainLayer,
  changeImageLayerShow,
} from './utils/initEarthLayers.js' // 导入封装的方法
import PoiSelector from './PoiSelector/Index.vue'
import Effect from './Effect/Index.vue'
import Fly from './Fly/Index.vue'
import PictureViewer from './PictureViewer/Index.vue'
import MorePicture from './MorePicture/Index.vue'
import VisualParameters from './VisualParameters/Index.vue'
import Tileset3D from './Tileset3D/Index.vue'
import Weather from './Weather/Index.vue'
import CeLiang from './CeLiang/Index.vue'
import ContextMenu from './ContextMenu/Index.vue' // 导入右键菜单组件
import { ElMessage } from 'element-plus' // 导入消息提示组件
const earth = ref(null)
// 使用inject获取objm
const objm = inject('objm')
// 右键菜单组件引用
const contextMenuRef = ref(null)

const state = ref(true) //显示纹理图层
const poiShow = ref(false) //显示POI标绘
const effectShow = ref(false) //特效
const picViewer = ref(false) //缩略图视角飞行定位
const morePic = ref(false) //多图视角飞行定位
const visual = ref(false) //可视化参数
const tileset3d = ref(false) //3dtileset模型
const weatherShow = ref(false) //天气
const ceLiangShow = ref(false) //测量

const humanData = ref([])
const humanPoiData = ref([])
const carData = ref([])

/**
 * 显示右键菜单
 * @param {MouseEvent} e - 鼠标右键事件对象
 */
const showContextMenu = (e) => {
  // 阻止默认的浏览器右键菜单
  e.preventDefault()

  // 调用右键菜单组件的显示方法
  if (contextMenuRef.value) {
    contextMenuRef.value.show(e)
  }
}

/**
 * 处理右键菜单命令
 * @param {Object} param - 包含命令和事件对象的参数
 * @param {string} param.command - 菜单命令
 * @param {MouseEvent} param.event - 原始鼠标事件
 */
const handleContextMenuCommand = ({ command, event }) => {
  console.log('执行命令:', command)

  // 根据不同命令执行相应操作
  switch (command) {
    case 'checkLocation':
      // 获取当前鼠标位置的地理坐标
      if (objm.activeViewer) {
        // 使用右键点击的屏幕位置
        const screenPosition = { x: event.clientX, y: event.clientY }

        // 调用地球SDK的拾取位置方法
        objm.activeViewer.pickPosition(screenPosition).then((position) => {
          if (position && position.length) {
            // 格式化坐标显示
            const formattedPosition = `
              经度: ${position[0].toFixed(6)}°
              纬度: ${position[1].toFixed(6)}°
              高度: ${position[2].toFixed(2)}米
            `
            console.log('当前位置坐标:', position)

            // 使用Element Plus的消息提示显示坐标
            ElMessage({
              message: formattedPosition,
              type: 'success',
              duration: 5000,
            })
          }
        })
      }
      break

    case 'checkView':
      // 获取当前视角信息
      if (objm.activeViewer) {
        const camera = objm.activeViewer.camera
        // 格式化视角信息
        const viewInfo = `
          位置: [${camera.position[0].toFixed(2)}, ${camera.position[1].toFixed(2)}, ${camera.position[2].toFixed(2)}]
          方向: ${camera.heading.toFixed(2)}°
          俯仰: ${camera.pitch.toFixed(2)}°
          翻滚: ${camera.roll.toFixed(2)}°
        `
        console.log('当前视角信息:', camera.position, camera.heading, camera.pitch, camera.roll)

        // 显示视角信息
        ElMessage({
          message: viewInfo,
          type: 'info',
          duration: 5000,
        })
      }
      break

    case 'measure1':
      // 启动距离量算功能
      console.log('启动距离量算')
      ceLiangShow.value = true
      // 这里可以调用量算组件的相关方法
      ElMessage({
        message: '已启动距离量算功能，请在地图上点击起点',
        type: 'info',
      })
      break

    case 'measure2':
      // 启动面积量算功能
      console.log('启动面积量算')
      ceLiangShow.value = true
      // 这里可以调用量算组件的相关方法
      ElMessage({
        message: '已启动面积量算功能，请在地图上绘制多边形',
        type: 'info',
      })
      break

    case 'effect1':
      // 雨天特效
      weatherShow.value = true
      // 调用天气组件的雨天方法
      ElMessage({
        message: '已开启雨天特效',
        type: 'success',
      })
      break

    case 'effect2':
      // 雪天特效
      weatherShow.value = true
      // 调用天气组件的雪天方法
      ElMessage({
        message: '已开启雪天特效',
        type: 'success',
      })
      break

    case 'mark1':
      // 点标记功能
      console.log('启动点标记')
      // 实现点标记逻辑
      ElMessage({
        message: '请在地图上点击添加标记点',
        type: 'info',
      })
      break

    case 'view1':
      // 切换到预设视角1
      if (objm.activeViewer) {
        // 这里可以设置预定义的视角参数
        objm.activeViewer.camera.flyTo({
          destination: [116.3, 39.9, 10000], // 示例坐标
          orientation: {
            heading: 0,
            pitch: -90,
            roll: 0,
          },
          duration: 2, // 飞行时间(秒)
        })
      }
      break

    // 其他命令的处理...
    default:
      console.log('未处理的命令:', command)
      ElMessage({
        message: `执行命令: ${command}`,
        type: 'info',
      })
  }
}

onMounted(() => {
  if (!earth.value) return
  //创建一个 Cesium 视口,并且绑定一个div容器 earth  // 注意：此时创建的只是一个空白地球，没有纹理
  // 创建Cesium视口,新创建的一个ESCzmViewer
  // 注意：若activeViewer不存在，创建之后会自动把这个ESCzmViewer 设置为activeViewer。
  // createCesiumViewer(domid, id,czmOptions)
  //  domid	  string	 HTMLElement	指定一个HTMLElement或者一个html元素标签id；
  // id	      string	 undefined	这个ESCzmViewer对象的id,不指定的话会自动创建;
  // czmOptions	{ [k: string]: any}	 undefined	  初始化Cesium viewer时的参数
  objm.createCesiumViewer(earth.value)

  // 创建UE视口 【返回值】新创建的一个ESUeViewer;
  // createUEViewer(domid, uri, app, id)
  // Name	    Type	    Description	          Default
  // domid	  string	 HTMLElement	         指定一个HTMLElement或者一个html元素标签id；
  // uri	    string	信令服务器地址
  // app	    string	信令服务器应用id
  // id	      string	undefined	          指定该对象的id,不指定的话会自动创建;

  const eSWidget = objm.createSceneObject(ESWidget)
  //createSceneObject(sceneObjectType, id)
  //创建场景对象  【返回值】一个新创建的SceneObject<T>或者undefined
  //  Name                    Type                     Description
  // sceneObjectType          string<T>               指定创建的对象类型名称或者类名 ，例如：'ESImageryLayer'
  // id                       string/undefined        指定该对象的id,不指定的话会自动创建;

  //Cesium  token
  objm.activeViewer.ionAccessToken =
    'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjNjVkZDYxOC01NmEwLTQ1ZmEtOGE2ZS1lYWUyODM4ZWQxYzQiLCJpZCI6MjU5LCJpYXQiOjE3NDYxMTA0Njl9.uyhPpCQKB1dodfbqTx0ZUPOLhnrSXd-qWixDxc4GYXk'

  // jsonLoadingEvent  每当默认场景树sceneTree.json加载的时候就会触发jsonLoadingEvent事件。
  //   objm.jsonLoadingEvent.don(e => {
  //     switch (e.type) {
  //         case "init":
  //             console.log("json init")
  //             break;
  //         case "loading":
  //             console.log("json loading")
  //             break;
  //         case "loaded":
  //             console.log("json loaded");
  //             break;
  //         case "error":
  //             console.log("json error", e.error);
  //             break;
  //     }
  // })
  //注意：先监听，再赋值json

  // // 通过json创建一个影像图层
  // objm.createSceneObjectFromJson({
  //   id: '9812a65f-0de0-4f7b-b234-809c0c2fb8ef',
  //   type: 'ESImageryLayer',
  //   url: 'https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
  // })
  // 3. 调用封装的方法加载影像 / 地形
  // initEarthLayers(objm, state.value)
  addESImageryLayer(objm) // 加载影像
  addESTerrainLayer(objm) // 加载地形
  //监听视口状态
  objm.activeViewer.statusChanged.don((value) => {
    console.log('监听视口的变化', value)
    if (value === 'Created') {
      console.log('statusChanged视口创建完成', value)
      // setTimeout(() => {
      //   //即使 statusChanged 触发 'Created'，Viewer 可能仍未完全加载地形或影像
      //   objm.activeViewer.flyIn(
      //     [109.00683438952149, 15.271693222726297, 2168741.372762946],
      //     [15.175646391806431, -55.3102300877878, 0.09839208246353574],
      //     3,
      //   )
      // }, 1000) // 延迟 1 秒确保 Viewer 完全就绪
    }
  })
  // viewerCreatedEvent  每当有新视口创建的时候便会触发这个事件

  // objm.viewerCreatedEvent.don((viewer) => {
  //   console.log('viewerCreatedEvent视口创建完成', viewer)
  //   viewer.clickEvent.don((e) => {
  //     console.log('鼠标单击click', e)
  //     //pick视口拾取方法   pick(screenPosition:屏幕坐标,attachedInfo:自定义属性,用于标识pick)
  //     viewer.pick(e.screenPosition, 'clickPick').then((res) => {
  //       // 全局拾取对象
  //       if (res && res.sceneObject) {
  //         console.log('拾取到的是：', res.sceneObject.name)
  //       }
  //     })
  //     //点击位置处的三维经纬高坐标
  //     viewer.pickPosition(e.screenPosition).then((res) => {
  //       console.log('点击位置处的三维经纬高坐标：', res)
  //     })
  //   })
  //   //双击事件dblclickEvent SDK3     dbclickEvent//SDK2
  //   viewer.dblclickEvent.don((e) => {
  //     console.log('鼠标双击dblclickEvent', e)
  //   })
  //   //hoverEvent 鼠标悬停事件 悬停时长可由viewer.hoverTime属性控制
  //   viewer.hoverEvent.don((e) => {
  //     console.log('鼠标悬浮事件hoverEvent', e)
  //     viewer.pick(e.screenPosition, 'hoverPick')
  //   })
  //   //#region
  //   // //鼠标移入事件
  //   // viewer.pointerOverEvent.don((e) => {
  //   //   console.log('鼠标移入事件ointerOverEvent', e)
  //   // })
  //   // //鼠标移出事件
  //   // viewer.pointerOutEvent.don((e) => {
  //   //   console.log('鼠标移出事件pointerOutEvent', e)
  //   // })
  //   // //鼠标移动事件
  //   // viewer.pointerMoveEvent.don((e) => {
  //   //   console.log('鼠标移动事件pointerMoveEvent', e)
  //   // })
  //   //#endregion
  // })
  //每当有新视口创建的时候便会触发这个事件
  objm.viewerCreatedEvent.don((viewer) => {
    // 监听clickEvent鼠标事件
    viewer.clickEvent.don((e) => {
      // pickPosition拾取经纬度
      viewer.pickPosition(e.screenPosition).then((position) => {
        if (!position || !position.length) return
        console.log('点击位置处的三维经纬高坐标：', position)
        eSWidget.position = [...position]
        if (humanData.value.length > 0) {
          humanData.value.forEach((item) => {
            // item.animation = 'running'
            item.smoothMove(position, 3)
          })
        }
        if (humanPoiData.value.length > 0) {
          humanPoiData.value.forEach((item) => {
            // item.animation = 'running'
            item.smoothMove(position, 10)
          })
        }
        if (carData.value.length > 0) {
          carData.value.forEach((item) => {
            // item.animation = 'running'
            item.smoothMove(position, 10)
          })
        }
      })
      // pick拾取
      viewer.pick(e.screenPosition, 'clickPick').then((res) => {
        // 判断是否拾取到信息
        if (!res || !res.tilesetPickInfo) {
          eSWidget.info = { title: '基本信息' }
          eSWidget.show = false
          return
        }
        console.log('拾取属性信息', res.sceneObject.name, res)
        // tilset属性信息
        const tilesetPickInfo = res.tilesetPickInfo
        // featureId
        const id = tilesetPickInfo['id']
        // 高亮Feature
        BIMtileset.value.resetFeatureStyle() //恢复feature，还原setFeatureVisable和setFeatureColor和setFeatureStyle的更改
        //根据属性名和条件值设置feature颜色；
        BIMtileset.value.setFeatureColor('id', [
          {
            value: id,
            rgba: [1, 0, 0, 1],
          },
        ])

        const data = {
          title: '基本信息',
          ...tilesetPickInfo,
        }
        eSWidget.info = data
        eSWidget.show = true
      })
      //   //hoverEvent 鼠标悬停事件 悬停时长可由viewer.hoverTime属性控制
      viewer.hoverEvent.don((e) => {
        console.log('鼠标悬浮事件hoverEvent', e)
        viewer.pick(e.screenPosition, 'hoverPick')
      })
    })

    //默认飞入点
    objm.activeViewer.flyIn(
      [120.26895628709843, 31.99890350891649, 1269.9201196285085],
      [333.4666903019263, -44.392623459065334, 0.0027997885275428858],
      3,
    )
  })
})
const BIMtileset = ref(null)
const handleBIMtilesetReady = (tileset) => {
  BIMtileset.value = tileset
  // console.log('接受Tileset3D 的 BIMtileset', tileset)
}

// emit触发handlePoiCreated  poi绑定控制台调试   //可直接在PoiSelector对应方法中绑定
const handlePoiCreated = ({ type, instance, humanArr, humanPoiArr, carArr }) => {
  if (humanArr) {
    humanData.value = humanArr
  }
  if (humanPoiArr) {
    humanPoiData.value = humanPoiArr
  }
  if (carArr) {
    carData.value = carArr
  }
  console.log(`创建的POI类型: ${type}`, instance)
  switch (type) {
    case 'image':
      window.ESimagepoi = instance
      break
    case '3d':
      window.ESpoi3d = instance
      break
    case '2d':
      window.ESpoi2d = instance
      break
    case 'human':
      window.EShuman = instance
      break
    case 'humanPoi':
      window.EShumanPoi = instance
      break
    case 'car':
      window.EScar = instance
      break
    default:
      console.warn(`未知的POI类型: ${type}`)
      break
  }
}

const switchToCesiumViewer = () => {
  if (!earth.value) return
  objm.switchToCesiumViewer(earth.value, undefined, undefined, true)
  //switchToCesiumViewer(domid, viewSync,attributeSync,destroy)
  // 切换Cesium视口 【返回值】一个ESCzmViewer ,将domid上的视口切换为ESCzmViewer视口
  // Name	              Type	      Description	  Default
  // domid	            string	    HTMLElement	  指定一个HTMLElement或者一个html元素标签id；
  // viewSync	          boolean	    undefined	    切换后是否同步到之前视口的视角，默认值 true
  // attributeSync	    boolean	    undefined	    是否同步两个视口的属性一次
  // destroy	          boolean	    undefined	    切换后是否销毁前一个视口
  // 注意：寻找管理器内部已经存在ESCzmViewer 的视口，不存在则会创建一个(createCesiumViewer)然后切换。
}
const switchToUEViewer = () => {
  if (!earth.value) return
  objm.switchToUEViewer(earth.value, 'http://localhost:9007/', 'demoUE5.3', true, undefined, true)
  //switchToUEViewer(domid, uri, app, viewSync,attributeSync,destroy)
  //切换UE视口  【返回值】一个ESUeViewer ,将domid上的视口切换为ESUeViewer视口；
  // Name	          Type	    Description	                Default
  // domid	        string	  HTMLElement	               指定一个HTMLElement或者一个html元素标签id；
  // uri	          string	  ESSS信令服务器地址
  // app	          string	  ESSS信令服务器应用id
  // viewSync	      boolean	  undefined	                切换后是否同步到之前视口的视角，默认为同步 true
  // attributeSync	boolean	  undefined	                是否同步两个视口的属性一次
  // destroy	      boolean	  undefined	                切换后是否销毁前一个视口
}
//注意：寻找管理器内部已经存在ESUeViewer的视口，不存在则会创建一个(createUEViewer)切换后返回。
</script>

<style lang="scss" scoped>
.nav-box {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  // height: 60px;
  background-color: rgba(0, 0, 0, 0.9);
  padding: 10px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  .changeViewer {
    display: flex;
    align-items: center;
    button {
      height: 40px;
    }
  }
  .switch {
    display: flex;
    align-items: center;
    gap: 10px;
    height: 40px;
    // background-color: #1690d9;
    color: #fff;
    padding: 10px;
    border-radius: 5px;
  }
}
.visual-slider-box {
  position: absolute;
  top: 120px;
  left: 540px;
  background-color: rgba(168, 193, 223, 0.3);
  padding: 20px;
  border-radius: 10px;
  .slider-demo-block {
    .demonstration {
      width: 80px;
      font-size: 14px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      color: #fff;
    }
    width: 200px;
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
  }
}
</style>
